package com.bsj.sipgateway.web.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.bsj.power.common.config.exception.ApiException;
import com.bsj.power.common.config.global.JsonResult;
import com.bsj.power.common.config.global.JsonResultEnum;
import com.bsj.power.common.config.redis.RedisConstant;
import com.bsj.power.common.def.dto.DeviceRegisterMidDTO;
import com.bsj.power.common.def.dto.FaultDTO;
import com.bsj.power.common.def.dto.FaultLogDTO;
import com.bsj.power.common.def.dto.video.FaultRecordDTO;
import com.bsj.power.common.def.entity.Fault;
import com.bsj.power.common.def.entity.FaultLog;
import com.bsj.power.common.def.vo.*;
import com.bsj.power.common.util.DateUtils;
import com.bsj.sipgateway.web.service.IAlarmService;
import com.bsj.sipgateway.web.service.IDeviceService;
import com.bsj.sipgateway.web.service.IFaultService;
import com.bsj.sipgateway.web.service.ISceneService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import redis.clients.bsj.JedisClusterBSJ;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 设备故障记录
 * @Author zhaoyang
 * @Date 2024/7/3 14:58
 * @menu 设备故障记录
 */
@Slf4j
@RestController
@RequestMapping("/api/fault")
//@SaCheckPermission("/video/api/fault")
public class ApiFaultController {

    @Autowired
    @Qualifier("faultServiceImpl")
    private IFaultService faultService;

    @Autowired
    @Qualifier("alarmServiceImpl")
    private IAlarmService alarmService;

    @Autowired
    @Qualifier("deviceServiceImpl")
    private IDeviceService deviceService;

    @Autowired
    @Qualifier("sceneServiceImpl")
    private ISceneService sceneService;


    @Autowired
    private JedisClusterBSJ jedisClusterBSJ;

    // 30天时间毫秒值
    private static final long timeMillis_30_days = 1000 * 60 * 60 * 24 * 30;


    /**
     * 新建
     *
     * @param faultDTO
     * @return
     */
    @PostMapping("/add")
    private JsonResult add(@RequestBody FaultDTO faultDTO) {
        boolean flag = faultService.add(faultDTO);
        if (flag) {
            return JsonResult.success();
        }
        return JsonResult.fail();
    }

    /**
     * 删除
     *
     * @param id
     * @return
     */
    @GetMapping("/delete")
    private JsonResult delete(@RequestParam Integer id) {
        if (id == null) {
            throw new ApiException(JsonResultEnum.PARAM_ERROR);
        }
        boolean flag = faultService.deleteById(id);
        if (flag) {
            return JsonResult.success();
        }
        return JsonResult.fail();
    }

    /**
     * 修改
     *
     * @param faultDTO
     * @return
     */
    @PostMapping("/update")
    private JsonResult update(@RequestBody FaultDTO faultDTO) {
        if (faultDTO == null || faultDTO.getId() == null) {
            throw new ApiException(JsonResultEnum.PARAM_ERROR);
        }
        boolean flag = faultService.update(faultDTO);
        if (flag) {
            return JsonResult.success();
        }
        return JsonResult.fail();
    }

    /**
     * 根据时间分页查询设备故障记录
     *
     * @param faultRecordDTO
     * @return
     */
    @PostMapping("/findFaultList")
    public JsonResult findFaultList(@RequestBody FaultRecordDTO faultRecordDTO) {
        return faultService.findFaultList(faultRecordDTO);
    }

    /**
     * 设备故障记录导出
     *
     * @param faultRecordDTO
     * @return
     */
    @SaIgnore
    @GetMapping("/faultListExport")
    public void faultListExport(HttpServletResponse response, FaultRecordDTO faultRecordDTO) throws IOException {
        List<FaultVO> vos = faultService.faultListExport(faultRecordDTO);
        List<FaultExportVO> faultExportVOS = new ArrayList<>();
        if (!CollectionUtils.isEmpty(vos)) {
            for (int i = 0; i < vos.size(); i++) {
                FaultVO faultVO = vos.get(i);
                FaultExportVO exportVO = new FaultExportVO();
                BeanUtils.copyProperties(faultVO, exportVO);
                exportVO.setSerialNum(i + 1);
                switch (faultVO.getFaultType()) {
                    case 1:
                        exportVO.setFaultType("异常排查");
                        break;
                    case 2:
                        exportVO.setFaultType("误报");
                        break;
                    case 3:
                        exportVO.setFaultType("设备故障");
                        break;
                    default:
                        exportVO.setFaultType("未知");
                        break;
                }
                faultExportVOS.add(exportVO);
            }
        }

        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        //编码 防止中文乱码
        String fileName = URLEncoder.encode("设备故障记录" + DateUtils.dateToStr(DateUtils.TIME_STANDARD_FORMAT2, new Date()), "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        EasyExcelFactory.write(response.getOutputStream(), FaultExportVO.class).sheet("设备故障记录")
                .doWrite(faultExportVOS);


    }


    /**
     * 场景设备故障次数排名
     *
     * @param beginTime
     * @param endTime
     * @return
     */
    @RequestMapping("/sceneDeviceFaultStatistics")
    public JsonResult sceneDeviceFaultStatistics(@RequestParam String beginTime, @RequestParam String endTime) {
        if (beginTime == null || endTime == null) {
            throw new ApiException(JsonResultEnum.PARAM_ERROR);
        }
        // 查询时间不能超过30天
        boolean flag = timeCheck(beginTime, endTime);
        if (!flag) {
            throw new ApiException(JsonResultEnum.TOO_MUCH_DAY_SPAN);
        }
        return faultService.sceneDeviceFaultStatistics(beginTime, endTime);
    }

    /**
     * 设备故障率统计
     *
     * @param beginTime
     * @param endTime
     * @return
     */
    @RequestMapping("/faultRateStatistics")
    private JsonResult faultRateStatistics(@RequestParam String beginTime, @RequestParam String endTime) {
        if (beginTime == null || endTime == null) {
            throw new ApiException(JsonResultEnum.PARAM_ERROR);
        }
        // 查询时间不能超过30天
        boolean flag = timeCheck(beginTime, endTime);
        if (!flag) {
            throw new ApiException(JsonResultEnum.TOO_MUCH_DAY_SPAN);
        }
//        List<AlarmReport> alarmReports = alarmService.findFaultAlarmByTime(beginTime, endTime);
        List<Fault> faultList = faultService.selectByTypeAndTime(beginTime, endTime, 3);
        JsonResult jsonResult = JsonResult.success();
        if (CollectionUtils.isEmpty(faultList)) {
            jsonResult.setData(0);
            return jsonResult;
        }

        // 统计设备id数量
        List<String> deviceNumberCount = faultList.stream().map(Fault::getDeviceNumber).distinct().collect(Collectors.toList());
        // 查询所有设备数量
        Long count = deviceService.findAllDeviceCount();
        int a = (int) (((float) deviceNumberCount.size() / count) * 100);
        jsonResult.setData(a);
        return jsonResult;
    }


    private static boolean timeCheck(String beginTime, String endTime) {
        if (beginTime == null || endTime == null) {
            return true;
        }
        long betweenTime = DateUtils.calculationTime(DateUtils.strToDate(beginTime), DateUtils.strToDate(endTime));
        return betweenTime >= timeMillis_30_days;
    }


    /**
     * 设备平均运行时长统计
     *
     * @param beginTime
     * @param endTime
     * @return
     */
    @RequestMapping("/deviceDurationStatistics")
    public JsonResult deviceDurationStatistics(@RequestParam String beginTime, @RequestParam String endTime) throws ParseException {
        // 查询时间不能超过30天
        boolean flag = timeCheck(beginTime, endTime);
        if (!flag) {
            throw new ApiException(JsonResultEnum.TOO_MUCH_DAY_SPAN);
        }
        List<DeviceDurationVO> durations = faultService.selectDeviceDurationByTime(beginTime, endTime);
        JsonResult jsonResult;
        if (CollectionUtils.isEmpty(durations)) {
            jsonResult = new JsonResult();
            jsonResult.setCode(-1);
            jsonResult.setMsg("暂无数据");
        }
        // 把durations按时间分组为map，key-date， value-List<DeviceDuration>
        Map<String, List<DeviceDurationVO>> collect = durations.stream().collect(Collectors.groupingBy(DeviceDurationVO::getRunDate));
        List<DurationStatisticVO> vos = new ArrayList<>();
        // 计算开始时间和结束时间之间的日期
        SimpleDateFormat sdf = new SimpleDateFormat(DateUtils.yearMonthDay);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(sdf.parse(beginTime));
        Date todayDate = new Date();
        long now = System.currentTimeMillis();
        for (long d = calendar.getTimeInMillis(); d <= sdf.parse(endTime).getTime(); d = get_D_Plaus_1(calendar)) {
            DurationStatisticVO vo = new DurationStatisticVO();
            Date date = new Date(d);
            boolean sameDay = DateUtils.isSameDay(todayDate, date);
            if (!sameDay) { // 如果不是今天的数据
                String format = sdf.format(d);
                List<DeviceDurationVO> deviceDurationVOS = collect.get(format);
                vo.setRunDate(format);
                vo.setTimeMillions(d);
                if (CollectionUtils.isEmpty(deviceDurationVOS)) {
                    vo.setTotalDurationTime(0);
                } else {
                    long sum = deviceDurationVOS.stream().mapToLong(DeviceDurationVO::getDurationTime).summaryStatistics().getSum();
                    // 毫秒转换为分钟
                    long minutes = sum / 1000 / 60;
                    vo.setTotalDurationTime(minutes);
                }
            } else {
                vo.setRunDate(sdf.format(todayDate));
                vo.setTimeMillions(todayDate.getTime());
                long todayTotalDurationTime = 0L;
                Map<String, String> stringStringMap = jedisClusterBSJ.hgetAll(RedisConstant.DEVICE_REGISTER_MID_DTO);
                for (Map.Entry<String, String> entry : stringStringMap.entrySet()) {
                    long did = Long.parseLong(entry.getKey());
                    String value = entry.getValue();
                    DeviceRegisterMidDTO midDTO = JSON.parseObject(value, DeviceRegisterMidDTO.class);
                    Long registerTime = midDTO.getRegisterTime();
                    Long logoutTime = midDTO.getLogoutTime();
                    long onlineTime = 0L;
                    if (logoutTime == null || logoutTime < registerTime) {
                        // 1、logoutTime为null,说明设备注册了，没注销，记录在线时长
                        // 2、logoutTime < registerTime 正常注册注销了，然后又注册了，没注销，记录在线时长
                        onlineTime = midDTO.getOnlineTime() + (now - registerTime);
                    } else {
                        // logoutTime > registerTime 说明设备正常注册注销了，只写入持续时间即可，不改变注册时间和注销时间，下次就不会统计了
                        onlineTime = midDTO.getOnlineTime();
                    }
                    todayTotalDurationTime += onlineTime;
                }
                vo.setTotalDurationTime(todayTotalDurationTime / 1000 / 60);
            }
            vos.add(vo);
        }

        List<DurationStatisticVO> sorted = vos.stream().sorted(Comparator.comparing(DurationStatisticVO::getTimeMillions)).collect(Collectors.toList());
        jsonResult = new JsonResult();
        jsonResult.setCode(JsonResultEnum.SUCCESS.getCode());
        jsonResult.setMsg(JsonResultEnum.SUCCESS.getMsg());
        jsonResult.setData(sorted);
        jsonResult.setTotal(sorted.size());
        return jsonResult;
    }

    private static long get_D_Plaus_1(Calendar calendar) {
        calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) + 1);
        return calendar.getTimeInMillis();
    }


    /**
     * 获取工单列表
     *
     * @param jobNum 支持对工单模糊查询,
     * @return
     */
    @GetMapping("/jobNumList")
    public JsonResult jobNumList(String jobNum) {
        return faultService.jobNumList(jobNum);
    }


    /**
     * 分页查询设备故障维护日志
     *
     * @param faultLogDTO
     * @return
     */
    @GetMapping("/listFaultLogs")
    public JsonResult<List<FaultLogVO>> listFaultLogs(FaultLogDTO faultLogDTO) {
        IPage<FaultLog> page = faultService.pageFaultLogList(faultLogDTO);
        if (page != null && page.getRecords() != null && page.getRecords().size() != 0) {
            List<FaultLog> records = page.getRecords();
            List<FaultLogVO> vos = new ArrayList<>();
            for (FaultLog record : records) {
                FaultLogVO vo = new FaultLogVO();
                vo.setId(record.getId());
//                vo.setJobNum(record.getJobNum());
                vo.setDeviceId(record.getDeviceId());
                vo.setCreateTime(DateUtils.dateToStr(record.getCreateTime()));
                vo.setFaultTime(DateUtils.dateToStr(record.getFaultTime()));
//                vo.setJobId(record.getJobId());
                vo.setNickName(record.getNickName());
                vo.setType(record.getType());
                vos.add(vo);
            }
            JsonResult jsonResult = JsonResult.success();
            jsonResult.setData(vos);
            jsonResult.setTotal(page.getTotal());
            return jsonResult;
        }
        JsonResult jsonResult = new JsonResult();
        jsonResult.setCode(-1);
        jsonResult.setMsg("暂无数据");
        return jsonResult;
    }


}
